#pragma once
#include <strmif.h>
#include <string>
#include "cfilereader.hpp"
#include <vector>

namespace MkvParser
{
class Segment;
class Cluster;
class Stream;
}

namespace MkvSource
{

class Outpin;

class Filter : public IBaseFilter, 
               public IFileSourceFilter,
               public IAMFilterMiscFlags
{
    friend HRESULT CreateInstance(
            IClassFactory*,
            IUnknown*, 
            const IID&, 
            void**);
    
    Filter(IClassFactory*, IUnknown*);
    virtual ~Filter();
    
    Filter(const Filter&);
    Filter& operator=(const Filter&);
    
public:

    //IUnknown

    HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);
    ULONG STDMETHODCALLTYPE AddRef();
    ULONG STDMETHODCALLTYPE Release();
    
    //IBaseFilter

    HRESULT STDMETHODCALLTYPE GetClassID(CLSID*);    
    HRESULT STDMETHODCALLTYPE Stop();    
    HRESULT STDMETHODCALLTYPE Pause();    
    HRESULT STDMETHODCALLTYPE Run(REFERENCE_TIME);    
    HRESULT STDMETHODCALLTYPE GetState(DWORD, FILTER_STATE*);    
    HRESULT STDMETHODCALLTYPE SetSyncSource(IReferenceClock*);
    HRESULT STDMETHODCALLTYPE GetSyncSource(IReferenceClock**);
    HRESULT STDMETHODCALLTYPE EnumPins(IEnumPins**);    
    HRESULT STDMETHODCALLTYPE FindPin(LPCWSTR, IPin**);    
    HRESULT STDMETHODCALLTYPE QueryFilterInfo(FILTER_INFO*);    
    HRESULT STDMETHODCALLTYPE JoinFilterGraph(IFilterGraph*, LPCWSTR);    
    HRESULT STDMETHODCALLTYPE QueryVendorInfo(LPWSTR*);

    //IFileSourceFilter
    
    HRESULT STDMETHODCALLTYPE Load(LPCOLESTR, const AM_MEDIA_TYPE*);    
    HRESULT STDMETHODCALLTYPE GetCurFile(LPOLESTR*, AM_MEDIA_TYPE*);
    
    //IAMFilterMiscFlags
    
    ULONG STDMETHODCALLTYPE GetMiscFlags();


    //local classes and methods

    void CreateOutpin(MkvParser::Stream*);

    class Lock
    {
        Lock(const Lock&);
        Lock& operator=(const Lock&);
    public:
        Lock();
        ~Lock();

        HRESULT Seize(Filter*, DWORD timeout = 5000);
        void Release();
    private:
        HANDLE m_hMutex;
    };
    
private:

    class nondelegating_t : public IUnknown
    {
    public:
    
        Filter* const m_pFilter;
        LONG m_cRef;
        
        explicit nondelegating_t(Filter*);
        virtual ~nondelegating_t();
        
        HRESULT STDMETHODCALLTYPE QueryInterface(const IID&, void**);
        ULONG STDMETHODCALLTYPE AddRef();
        ULONG STDMETHODCALLTYPE Release();

    private:

        nondelegating_t(const nondelegating_t&);
        nondelegating_t& operator=(const nondelegating_t&);

    };
    
    IClassFactory* const m_pClassFactory;
    nondelegating_t m_nondelegating;
    IUnknown* const m_pOuter;  //decl must follow m_nondelegating
    REFERENCE_TIME m_start;
    IReferenceClock* m_clock;
    FILTER_INFO m_info;
    HANDLE m_hMutex;
    
public:
    static const LONGLONG kNoSeek;

    FILTER_STATE m_state;
    CFileReader m_file;
    std::wstring m_filename;
    MkvParser::Segment* m_pSegment;
    MkvParser::Cluster* m_pSeekBase;
    __int64 m_seekTime;
    
    typedef std::vector<Outpin*> pins_t;
    pins_t m_pins;
    
    int GetConnectionCount() const;
    
private:
    
    //HANDLE m_hThread;
    //HANDLE m_hStop;
    //
    //static unsigned __stdcall ThreadProc(void*);
    //unsigned Main();
    
    //void Init();
    //void Final();
    void OnStop();
    void OnStart();

    HRESULT CreateSegment();
    void PopulateSamples(const HANDLE*, DWORD);
    
#if 0    
    template<typename T, typename S>
    struct TCreatePins
    {
        Filter* f;
        
        typedef S* (*pfn_t)(T*);
        pfn_t pfn;
        
        TCreatePins(Filter* f_, pfn_t pfn_) : f(f_), pfn(pfn_) {}
        void operator()(T* t) const
        {
            if (S* s = (*pfn)(t))
            {
                Outpin* const p = new (std::nothrow) Outpin(f, s);
                f->m_pins.push_back(p);
            }
        }
    };
#endif
     
};

}  //end namespace MkvSource

